package com.kimehwa.studyboot.basejava.generic;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.assertj.core.api.ObjectEnumerableAssert;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class GenericDemo2 {
    public static void main(String[] args) {
        ArrayList<Chinese> chineseArrayList = new ArrayList<>();
        chineseArrayList.add(new Chinese("李健"));
        chineseArrayList.add(new Chinese("周深"));

        ArrayList<Japanese> japaneseArrayList = new ArrayList<>();
        japaneseArrayList.add(new Japanese("三浦春马"));
        japaneseArrayList.add(new Japanese("瑛太"));

        /**
         * 与编译器约定，左右两边类型不一致也能赋值，但是有条件：
         * 右边List的参数类型必须是Human的子类,  继承的话只支持读取
         *
         * List<? extends Human>指向：只能指向子类型List，比如List<Chinese>，Human是最上边的类
         * List<? extends Human>取出：接上一条限制，不论指向什么List元素必然是Human及其子类型，按Human转
         * List<? extends Human>存入：简单泛型要是能解决早解决了，还轮得到我？直接禁止存入，溜了溜了
         */
        List<? extends Human> humanList =chineseArrayList;
        Human lee = humanList.get(0);
        Human chou = humanList.get(1);
        System.out.println(lee + "&" + chou);

        humanList = japaneseArrayList;
        Human haRuMa = humanList.get(0);
        Human eiTa = humanList.get(1);
        System.out.println(haRuMa + "&" + eiTa);
//        ------------ 范型继承的话 不支持存取 ------
//        -----------下接通配符 super------------



    }

    /**
     * super 存取 只能是子类型
     * List<? super Human>接收：只能指向父类型List，比如List<Creature>、List<Primate>
     * List<? super Human>取出：只能转Object
     * List<? super Human>存入：只能存Human及其子类型元素
     */

    @Test
    void testSuper(){
        List<? super Human> humanList = new ArrayList<>();
        // 别紧张，还没开始呢，我现在自己指向自己，还不让存东西了吗？
        humanList.add(new Human("人类"));

        // 只能指向Human及其父类型的List：灵长类、生物类
        // humanList = new ArrayList<Chinese>(); // ERROR
        humanList = new ArrayList<Primate>();
        humanList = new ArrayList<Creature>();

        // 哇，牛逼啊，简单泛型和extends都搞不定的存入问题让你super整得服服帖帖
        humanList.add(new Human("女性"));
        humanList.add(new Chinese("中国人"));

        // super：也不是啦，我虽然能存东西，但规定只能存Human及其子类型元素
//        humanList.add(new Primate("灵长类动物")); // ERROR
//        humanList.add(new Creature("外星生物")); // ERROR
//        humanList.add("无关类型，比如String"); // ERROR

        // 简单类型&extends：哈哈哈，你这啥玩意，怎么只能往Object自动转型
        Object object = humanList.get(0);
        List<Object> list = Collections.singletonList(new ArrayList<Integer>());
        // 无界通配符的一些使用总结
        List<?> list1 = new ArrayList<>();
//        list1.add(1);
        List<Object> list2= new ArrayList<>();
        list2.add(1);
        List<?> list3 = new ArrayList<String>();
//        list3.add("123");

    }

    /**
     * 无界通配符 ，它类似于List<? extends Object>，允许指向任意类型的List。
     */

    static class Creature {
        public Creature(String name) {
            this.name = name;
        }
        private String name;
    }

    static class Primate extends Creature {
        public Primate(String name) {
            super(name);
        }
    }





    static class Human extends Primate {
        public Human(String name) {
            super(name);
        }
    }
    public static class Chinese extends Human {
        public Chinese(String name) {
            super(name);
        }
    }

    public static class Japanese extends Human {
        public Japanese(String name) {
            super(name);
        }
    }

}

